﻿
namespace HSS.ServiceModel.Internal
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.Reflection;
	using System.Reflection.Emit;
	#endregion

	#region AsyncServiceInterfaceFactory
	/// <summary>
	/// A dynamic Service factory.
	/// </summary>
	internal class AsyncServiceInterfaceFactory
	{
		#region Fields
		static readonly Lazy<AsyncServiceInterfaceFactory> singleton = new Lazy<AsyncServiceInterfaceFactory>(() => new AsyncServiceInterfaceFactory(), true);
		private readonly Dictionary<Type, Type> generated = new Dictionary<Type, Type>();
		private readonly ModuleBuilder module;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		public AsyncServiceInterfaceFactory()
		{
			var assemblyName = new AssemblyName("HSS.ServiceModel.Internal.Auto");

			var appDomain = AppDomain.CurrentDomain;
			var assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);

			module = assemblyBuilder.DefineDynamicModule("HSS.ServiceModel.Internal.Auto.dll");
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the current instance.
		/// </summary>
		public static AsyncServiceInterfaceFactory Instance
		{
			get { return singleton.Value; }
		}
		#endregion

		#region Methods
		/// <summary>
		/// Generates the Async version of the Service.
		/// </summary>
		/// <param name="syncInterface">The standard service interface type.</param>
		/// <returns>The Async version Type of the Service.</returns>
		public Type Generate(Type syncInterface)
		{
			lock (generated)
			{
				if (!generated.ContainsKey(syncInterface))
					generated[syncInterface] = GenerateAsyncInterface(syncInterface);

				return generated[syncInterface];
			}
		}
		/// <summary>
		/// Generates the actual dynamic async interface.
		/// </summary>
		/// <param name="syncInterface">The sync version of the interface to use as the template.</param>
		/// <returns>The Async version Type of the Service.</returns>
		Type GenerateAsyncInterface(Type syncInterface)
		{
			var generator = new AsyncServiceInterfaceGenerator(module, syncInterface);
			return generator.Generate();
		}
		#endregion
	}
	#endregion
}